package cn.blnp.net.flowable.transfer.gateway.event;

import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <h3>网关-事件网关</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/19 17:28
 */
@Slf4j
@SpringBootTest
public class EventGatewayTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    /**
     *  <h2>事件网关</h2>
     *  <p>
     *      通常网关基于连线条件决定后续路径，但事件网关有所不同，其基于事件决定后续路径。事件网关的每条外出顺序流都需要连接一个捕获中间事件。事件网关只有分支行为，
     *  流程的走向完全由中间事件决定，允许从多条候选分支中选择事件最先到达的分支（如时间事件、消息事件），并取消其他分支。
     *  </p>
     *  <h3>案例演示</h3>
     *  <p>
     *      该流程为客户投诉处理流程。“客户投诉”提交发起的流程执行到事件网关时会暂停执行。与此同时，流程实例会订阅信号事件，并创建一个30分钟后触发的定时器。这使得工作流
     *  引擎等待信号事件30分钟：如果信号在30分钟内触发，则定时器会被取消，执行沿着信号继续，流转到“一线客服处理”节点；如果30分钟内信号未被触发，执行会在定时器到时后继续，
     *  流程沿着定时器方向流转到“二线客服处理”节点，同时取消信号订阅。<br/>
     *      <b>流程定义文件：</b>{@link flow/eventGatewayProcess.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/19/682afb7d4c1d8.png" />
     *  </p>
     **/
    @Test
    public void test() throws InterruptedException {
        Deployment deploy = repositoryService.createDeployment()
                .name("事件网关-演示案例")
                .addClasspathResource("flow/eventGatewayProcess.bpmn20.xml")
                .deploy();
        log.info("部署流程定义：{}", deploy.getId());
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义编号：{}", procDef.getId());
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(procDef.getId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());

        //查询并办理第一个任务
        Task task1 = taskQuery.singleResult();
        taskService.complete(task1.getId());
        //查询执行实例
        List<Execution> executionList = runtimeService.createExecutionQuery()
                .processInstanceId(procInst.getId())
                .onlyChildExecutions().list();
        log.info("第一个任务办理后，当前流程所处节点为：{}", executionList.stream()
                .map(Execution::getActivityId).collect(Collectors.joining(",")));
        //等待5分钟
        Thread.sleep(1000 * 60 * 5);
        //触发信号
        runtimeService.signalEventReceived("alert");
        Task task2 = taskQuery.singleResult();
        log.info("触发信号后，当前流程所处用户任务名称：{}", task2.getName());
        //办理任务
        taskService.complete(task2.getId());

        /**
         *  演示结果：
         *  2025-05-19 17:38:33.135  INFO 58508 --- [           main] c.b.n.f.t.g.event.EventGatewayTest       : 部署流程定义：06755750-3495-11f0-9ca9-50ebf6ec8f6d
         * 2025-05-19 17:38:33.143  INFO 58508 --- [           main] c.b.n.f.t.g.event.EventGatewayTest       : 流程定义编号：eventGatewayProcess:1:07910083-3495-11f0-9ca9-50ebf6ec8f6d
         * 2025-05-19 17:38:34.007  INFO 58508 --- [           main] c.b.n.f.t.g.event.EventGatewayTest       : 第一个任务办理后，当前流程所处节点为：intermediateCatchEvent1,intermediateCatchEvent2
         * 2025-05-19 17:43:34.072  INFO 58508 --- [           main] c.b.n.f.t.g.event.EventGatewayTest       : 触发信号后，当前流程所处用户任务名称：二线客服处理
         **/
    }
}
